#pragma once
#include "../core.h"

namespace qb{
	namespace base{
		class S_CORE_EXPORT MD5{
		public:
			typedef char tMD5[36];
		static bool FromString(const char* szStr, char* md5buf, int len);
		static bool FromString(const char* szStr,int szStrLen, char* md5buf, int len);
		static bool FromFile(const char* szFileName, char* md5buf, int len);
		};
	}

    typedef unsigned       int uint4;
    typedef unsigned short int uint2;
    typedef unsigned      char uchar;


    S_CORE_EXPORT char* PrintMD5(uchar md5Digest[16]);
    S_CORE_EXPORT char* MD5String(const char* szString);
    S_CORE_EXPORT char* MD5File(char* szFilename);

    S_CORE_EXPORT void Init();
    S_CORE_EXPORT void Update(uchar* chInput, uint4 nInputLen);
    S_CORE_EXPORT void Finalize();
    S_CORE_EXPORT uchar* Digest();// { return m_Digest; }

    S_CORE_EXPORT void Transform(uchar* block);
    S_CORE_EXPORT void Encode(uchar* dest, uint4* src, uint4 nLength);
    S_CORE_EXPORT void Decode(uint4* dest, uchar* src, uint4 nLength);

    inline uint4 rotate_left(uint4 x, uint4 n)
    { return ((x << n) | (x >> (32-n))); }

    inline uint4 F(uint4 x, uint4 y, uint4 z)
    { return ((x & y) | (~x & z)); }

    inline uint4 G(uint4 x, uint4 y, uint4 z)
    { return ((x & z) | (y & ~z)); }

    inline uint4 H(uint4 x, uint4 y, uint4 z)
    { return (x ^ y ^ z); }

    inline uint4 I(uint4 x, uint4 y, uint4 z)
    { return (y ^ (x | ~z)); }

    inline void FF(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac)
    { a += F(b, c, d) + x + ac; a = rotate_left(a, s); a += b; }

    inline void GG(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac)
    { a += G(b, c, d) + x + ac; a = rotate_left(a, s); a += b; }

    inline void HH(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac)
    { a += H(b, c, d) + x + ac; a = rotate_left(a, s); a += b; }

    inline void II(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac)
    { a += I(b, c, d) + x + ac; a = rotate_left(a, s); a += b; }

    static unsigned char PADDING[64] =
    {
        0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
    };

}
